package infos

import (
	"fmt"
	"time"

	"gogs.xiaoyuanjijiehao.com/antlinker/antcms/internal/json"

	"gogs.xiaoyuanjijiehao.com/antlinker/antcms/app/sysparam"

	"github.com/gin-gonic/gin"
	"github.com/pkg/errors"
	"gogs.xiaoyuanjijiehao.com/antlinker/antcms/app/ginsrv/api/base"
	"gogs.xiaoyuanjijiehao.com/antlinker/antcms/core"
	"gogs.xiaoyuanjijiehao.com/antlinker/antcms/core/columnd"
	"gogs.xiaoyuanjijiehao.com/antlinker/antcms/core/common"
	"gogs.xiaoyuanjijiehao.com/antlinker/antcms/core/factory"
	"gogs.xiaoyuanjijiehao.com/antlinker/antcms/core/groupd"
	"gogs.xiaoyuanjijiehao.com/antlinker/antcms/core/infod"
	"gogs.xiaoyuanjijiehao.com/antlinker/antcms/core/interactiond"
	"gogs.xiaoyuanjijiehao.com/antlinker/antcms/core/orgd"
	"gogs.xiaoyuanjijiehao.com/antlinker/antcms/core/util"
	"gogs.xiaoyuanjijiehao.com/antlinker/antcms/ddd"
	"gogs.xiaoyuanjijiehao.com/antlinker/antcms/evt/userclievt"
	"gogs.xiaoyuanjijiehao.com/antlinker/antcms/log"
)

type respInfo struct {
	InfoID       string                 `json:"info_id"` // 信息编码
	Seq          string                 `json:"page_id"` // 序列,如果存在用这个字段作为分页的pageID
	ColumnName   string                 `json:"column_name"`
	ColumnID     string                 `json:"column_id"`               // 所属栏目
	Owner        string                 `json:"owner"`                   // 所有者
	Org          string                 `json:"org"`                     // 所属组织
	Kind         int                    `json:"kind"`                    // 类型 1.文章，2短文，3投票，活动，调查问卷
	Title        string                 `json:"title"`                   // 标题
	SubTitle     string                 `json:"sub_title"`               // 副标题标题
	ListMode     int                    `json:"list_mode"`               // 列表展示时的默认模式
	Icon         []string               `json:"icon"`                    // 图标
	Banner       string                 `json:"banner"`                  // 旗帜
	Desc         string                 `json:"desc"`                    // 简介
	Tags         []string               `json:"tags"`                    // 标签列表
	From         string                 `json:"from"`                    // 来源
	Content      string                 `json:"content,omitempty"`       // 信息内容
	CheckContent string                 `json:"check_content,omitempty"` // 审核理由
	PublishTime  time.Time              `json:"publish_time"`            // 发布时间
	CreTime      *time.Time             `json:"cre_time"`                //创建时间
	Creator      string                 `json:"creator"`                 // 创建人
	Extras       map[string]interface{} `json:"extras"`                  //扩展信息
	Status       int                    `json:"status"`                  // 状态
	CtlParam     *infoCtrlParam         `json:"ctl_param,omitempty"`     // 控制参数
	URL          string                 `json:"url,omitempty"`
	Totals       infoTotal              `json:"totals"`
	My           my                     `json:"my"`
}

type infoTotal struct {
	ReplayNum int `json:"replay_num,omitempty"`
	LikeNum   int `json:"like_num,omitempty"`
	CollNum   int `json:"coll_num,omitempty"`
}

// type infoCtrlParam struct {
// 	IsReply      int      `json:"is_reply"`       // 是否开启信息评论 0 不开启 1 开启
// 	AllowIntCode []string `json:"allow_int_code"` // 允许的互动模式 对应InteractionTypeDesc中的Code
// 	IsShare      int      `json:"is_share"`       // 是否开启分享 0 不开启 1 开启
// 	IsCollect    int      `json:"is_collect"`     // 是否开启收藏  0 不开启 1 开启
// 	MyLike       int      `json:"my_like"`        // 是否我已经点赞  0 否 1 是
// 	MyColl       int      `json:"my_coll"`        // 是否我已经点赞  0 否 1 是
// }
type my struct {
	Like bool `json:"like"`
	Coll bool `json:"coll"`
}
type infoCtrlParam struct {
	IsReply int `json:"is_reply"` // 是否开启信息评论 0 不开启 1 开启
	IsShare int `json:"is_share"` // 是否开启分享 0 不开启 1 开启
	IsLike  int `json:"is_like"`
	IsColl  int `json:"is_coll"`
}

func createInfoCtrl(d core.CmsDomain) *infoCtrl {
	return &infoCtrl{
		BaseContrl: base.BaseContrl{
			Domain: d,
		},
		info: d.Info(),
		iar:  d.Info().InfoAggregateRoot(),
		car:  d.Column().ColumnAggregateRoot(),
		gar:  d.Group().GroupAggregateRoot(),
		oar:  d.Org().OrgAggregateRoot(),
		iiar: d.Interaction().InteractionAggregateRoot(),
		igar: d.Interaction().GroupAggregateRoot(),
	}
}

type infoCtrl struct {
	base.BaseContrl
	info infod.InfoDomain
	iar  infod.InfoAggregateRoot
	car  columnd.ColumnAggregateRoot
	gar  groupd.GroupAggregateRoot
	oar  orgd.OrgAggregateRoot
	iiar interactiond.InteractionAggregateRoot
	igar interactiond.GroupAggregateRoot
}

// // InfoSearch 查询条件
// type InfoSearch struct {
// 	// UID OrgID 如果都为空 :
// 	// 	 Range 0 查询所有信息包含 所有者和所属组织的信息
// 	// 	Range  1 查询除所属组织所属用户以外的信息
// 	// UID OrgID 任何一个不为空：
// 	// 	  Range 参数失效
// 	Range    int      `from:"range"`
// 	UID      string   `from:"owner"`  // 所有者用户编号
// 	OrgID    string   `from:"org"`    // 组织编号
// 	ColumnID string   `from:"column"` // 栏目编号
// 	Key      string   `from:"key"`    // 关键字
// 	Tags     []string `from:"tags"`   //  匹配标签

// }

func (c infoCtrl) parseInfoSearch(ctx *gin.Context) (result infod.InfoSearch) {

	result.ColumnID = ctx.DefaultQuery("column", "")
	result.Key = ctx.DefaultQuery("key", "")
	result.OrgID = ctx.DefaultQuery("org", "")
	result.Tags, _ = ctx.GetQueryArray("tags")
	result.Range = c.GetIntByQuery(ctx, "range", 1)
	result.Status = []infod.IStatus{infod.IStatusPublished}
	if extrastr, ok := ctx.GetQuery("extral"); ok && extrastr != "" {
		if err := json.Unmarshal([]byte(extrastr), &result.Extral); err != nil {
			return
		}
	}
	return
}
func (c infoCtrl) parseMyInfoSearch(ctx *gin.Context) (result infod.InfoSearch) {
	result.ColumnID = ctx.DefaultQuery("column", "")
	result.Key = ctx.DefaultQuery("key", "")
	result.Tags, _ = ctx.GetQueryArray("tags")
	result.Range = c.GetIntByQuery(ctx, "range", 1)
	result.Status = []infod.IStatus{
		infod.IStatusPublished,
		infod.IStatusNoPublish,
		infod.IStatusCheckWait,
		infod.IStatusCheckOk,
		infod.IStatusProhibitPublish,
		infod.IStatusPublished,
	}
	if extrastr, ok := ctx.GetQuery("extral"); ok && extrastr != "" {
		if err := json.Unmarshal([]byte(extrastr), &result.Extral); err != nil {
			return
		}
	}
	return
}

// 分页获取信息列表
func (c infoCtrl) getInfoPageList(ctx *gin.Context) {

	page := c.GetPageInfo(ctx, common.PageModeID)
	dctx := c.DDDContext(ctx)
	sch := c.parseInfoSearch(ctx)
	pr, cs, err := c.iar.QueryPage(dctx, sch, page)
	if err != nil {
		c.ErrServerError(ctx, 1, "查找信息列表失败", errors.Wrap(err, "查找信息列表失败"))
		return
	}
	var respInfos []interface{}
	for _, v := range cs {
		col, err1 := c.car.GetColumn(dctx, v.ColumnID)
		if err1 != nil {
			c.ErrServerError(ctx, 33, "查询文章所在栏目信息失败", errors.Wrapf(err, "查询信息(%v)所在栏目信息失败.", v.InfoID))
			err = err1
			return
		}
		respInfos = append(respInfos, adapterC2Resp(ctx, &v, col))
	}
	c.SuccessPage(ctx, page, pr, respInfos)
}

// 分页获取信息列表
func (c infoCtrl) getMyInfoPageList(ctx *gin.Context) {
	// 获取分页信息
	page := c.GetPageInfo(ctx, common.PageModeID)
	dctx := c.DDDContext(ctx)
	// 获取查询条件
	sch := c.parseMyInfoSearch(ctx)
	// 指定当前用户
	sch.UID = dctx.UID()
	if dctx.UID() == "" {
		c.ErrForbidden(ctx, "未登录不能访问")
		return
	}
	// 查询信息
	pr, cs, err := c.iar.QueryPage(dctx, sch, page)
	if err != nil {
		c.ErrServerError(ctx, 1, "查找信息列表失败", errors.Wrap(err, "查找信息列表失败"))
		return
	}
	// 获取适配器
	adapter := ctx.Param("show")
	if adapter == "" {
		adapter = showModeMyInfo
	}
	// 接口适配输出
	var respInfos []interface{}
	for _, v := range cs {
		col, err1 := c.car.GetColumn(dctx, v.ColumnID)
		if err1 != nil {
			c.ErrServerError(ctx, 33, "查询文章所在栏目信息失败", errors.Wrapf(err, "查询信息(%v)所在栏目信息失败.", v.InfoID))
			err = err1
			return
		}
		respInfos = append(respInfos, adapterC2RespForCode(ctx, adapter, &v, col))
	}
	// 返回接口数据
	c.SuccessPage(ctx, page, pr, respInfos)
}

// 获取指定信息
func (c infoCtrl) getInfo(ctx *gin.Context) {

	infoid := ctx.Param("infoid")
	dctx := c.DDDContext(ctx)
	if infoid == "" {
		c.ErrBadRequest(ctx, 1, "请求参数错误", nil)
		return
	}
	ia, err := c.iar.GetInfo(dctx, infoid)
	if err != nil {
		c.ErrServerError(ctx, 2, "查找信息失败", errors.Wrapf(err, "检测信息(%v)是否存在失败：", infoid))
		return
	}
	if ia == nil {
		c.ErrNotFound(ctx, 3, "信息不存在", nil)
		return
	}
	uid := dctx.UID()
	if ia.Owner != uid && ia.Status != infod.IStatusPublished {
		// 不是自己的信息只能获取发布信息
		c.ErrBadRequest(ctx, 4, "文章不存在或没有发布不能访问", nil)
		return
	}
	col, err := c.car.GetColumn(dctx, ia.ColumnID)
	if col == nil {
		c.ErrServerError(ctx, 5, "查询文章所在栏目信息失败", errors.Wrapf(err, "查询信息(%v)所在栏目信息失败.", infoid))
		return
	}

	icp := &infoCtrlParam{
		IsReply: col.IsReply,
		IsShare: 1,
	}

	intTypeLikeCode := sysparam.IntsLikeCode()
	intTypeCollCode := sysparam.IntsCollectionCode()

	if g, err := factory.DefaultFactory.GetOrCreIGroup(dctx, interactiond.IGTTInfo, infoid); err == nil && g != nil {
		for _, v := range g.AllowCodes {
			switch v {
			case intTypeLikeCode:
				icp.IsLike = 1
			case intTypeCollCode:
				icp.IsColl = 1
			default:
			}
		}
	} else {
		c.ErrServerError(ctx, 5, "获取信息详情失败", errors.Wrapf(err, "查询信息(%v)所在互动组信息失败.", infoid))
		return
	}

	ri := &respInfo{
		InfoID:       ia.InfoID,
		ColumnID:     ia.ColumnID,
		ColumnName:   col.Name,
		Kind:         ia.Kind,
		Title:        ia.Title,
		SubTitle:     ia.SubTitle,
		ListMode:     ia.ListMode,
		Icon:         ia.Icon,
		Banner:       ia.Banner,
		From:         ia.From,
		Desc:         ia.Desc,
		Tags:         ia.Tags,
		Extras:       ia.Extras,
		PublishTime:  ia.PublishTime,
		CheckContent: ia.CheckContent,
		Creator:      ia.Creator,
		Content:      ia.Content,
		Owner:        ia.Owner,
		Org:          ia.Org,
		CtlParam:     icp,
	}
	if uid != "" {
		if num, err := c.iiar.QueryNum(dctx, interactiond.InteractionSearch{
			Codes: []string{intTypeLikeCode},
			IGID:  []string{c.igar.ID(interactiond.IGTTInfo, ia.InfoID)},
			UID:   []string{uid},
		}); err != nil {
			log.Warnf("查询我是否点赞失败")
		} else if num > 0 {
			ri.My.Like = true
		}
		if num, err := c.iiar.QueryNum(dctx, interactiond.InteractionSearch{
			Codes: []string{intTypeCollCode},
			IGID:  []string{c.igar.ID(interactiond.IGTTInfo, ia.InfoID)},
			UID:   []string{uid},
		}); err != nil {
			log.Warnf("查询我是否点赞失败")
		} else if num > 0 {
			ri.My.Coll = true
		}
	}
	if g, err := c.igar.GetIGroup2(dctx, interactiond.IGTTInfo, ia.InfoID); err != nil {
		log.Warnf("获取统计信息失败")
	} else if g != nil {

		ri.Totals.ReplayNum = g.ReplayNum
		for _, v := range g.GroupTotal {
			switch v.ITCode {
			case intTypeLikeCode:
				ri.Totals.LikeNum = v.Total
			case intTypeCollCode:
				ri.Totals.CollNum = v.Total
			default:
			}

		}
	}
	// 创建用户浏览信息事件
	userclievt.TriggerLookInfoEvent(ctx.Request.RequestURI, uid, interactiond.IGTTInfo, infoid)
	c.Success(ctx, ri)
}

// ReqInfoDesc 请求参数
type ReqInfoDesc struct {
	ColumnID string                 `json:"column_id" binding:"required,max=32"`
	Kind     int                    `json:"kind" binding:"required,gte=1,lte=5"`         // 类型 1.文章，2短文，3投票，4活动，5调查问卷
	Title    string                 `json:"title" binding:"required,max=100"`            // 标题
	SubTitle string                 `json:"sub_title,omitempty" binding:"max=100"`       // 副标题标题
	ListMode int                    `json:"list_mode,omitempty"`                         // 列表展示时的默认模式
	Icon     []string               `json:"icon,omitempty" binding:"max=9,dive,max=500"` // 图标
	Banner   string                 `json:"banner,omitempty" binding:"max=500"`          // 封面
	From     string                 `json:"from,omitempty" binding:"max=500"`            // 来源
	Desc     string                 `json:"desc,omitempty" binding:"max=500"`            // 简介
	Tags     []string               `json:"tags,omitempty" binding:"max=20,dive,max=20"` // 标签列表
	Content  string                 `json:"content,omitempty" binding:"max=5000"`        // 信息内容
	Extras   map[string]interface{} `json:"extras,omitempty" binding:"max=20"`           // 扩展信息
}

// To 转换为infod.InfoDesc
func (r ReqInfoDesc) To() infod.InfoDesc {
	return infod.InfoDesc{
		ColumnID: r.ColumnID,
		Kind:     r.Kind,
		Title:    r.Title,
		SubTitle: r.SubTitle,
		ListMode: r.ListMode,
		Icon:     r.Icon,
		From:     r.From,
		Banner:   r.Banner,
		Desc:     r.Desc,
		Tags:     r.Tags,
		Content:  r.Content,
		Extras:   r.Extras,
	}
}

func (c infoCtrl) addInfo(ctx *gin.Context) {
	var req ReqInfoDesc

	if err := ctx.BindJSON(&req); err != nil {
		c.ErrBadRequestByBind(ctx, 1, err)
		return
	}
	dctx := c.DDDContext(ctx)
	uid := dctx.UID()
	if uid == "" {
		c.ErrUnauthorized(ctx, "保存失败：未登录")
		return
	}
	desc := req.To()
	col, err := c.car.GetColumn(dctx, desc.ColumnID)
	if err != nil {
		c.ErrServerError(ctx, 2, "保存失败", errors.Wrap(err, "检测栏目是否存在失败."))
		return
	}
	if col == nil {
		c.ErrBadRequest(ctx, 3, "栏目不存在")
		return
	}
	if col.Status != 0 {
		c.ErrBadRequest(ctx, 4, "栏目状态不对，不能添加信息")
		return
	}
	if col.ProhibitPostInfo == columnd.On {
		c.ErrBadRequest(ctx, 5, "栏目禁止发文章")
		return
	}
	if col.IsSubmit == 0 {
		c.ErrBadRequest(ctx, 6, "栏目模式,禁止投稿不能发信息")
		return
	}
	if dctx.UID() == "" {
		c.ErrUnauthorized(ctx, "未登录不能发布信息")
		return
	}
	if col.Owner != "" && dctx.UID() != col.Owner {
		c.ErrForbidden(ctx, "用户没有权限在该栏目发信息")
		return
	}
	if col.Org != "" {
		c.ErrForbidden(ctx, "用户没有权限在该栏目发信息")
		return
	}
	if col.Owner != "" || col.Org != "" {
		desc.Org = col.Org
		desc.Owner = col.Owner
	} else {
		desc.Owner = uid
	}
	if err := util.CheckInfoExtral(col.Extras, req.Extras); err != nil {
		c.ErrServerError(ctx, 6, fmt.Sprintf("保存失败:%v", err.Error()), errors.Wrapf(err, "扩展信息检测失败"))
		return
	}
	if col.InfoMode == columnd.InfoModeSingle {
		// 单文章模式发文章
		id, err := c.addSingleInfo(dctx, col, &desc)
		if err != nil {
			c.ErrServerError(ctx, 7, "保存失败", errors.Wrapf(err, "单文章模式发文失败"))
			return
		}
		c.Success(ctx, map[string]interface{}{"info_id": id})
		return
	}
	// 新增信息
	id, err := c.iar.AddInfo(dctx, desc)
	if err != nil {
		c.ErrServerError(ctx, 6, "保存失败", errors.Wrap(err, "新增信息失败："))
		return
	}
	// 获取新增的信息
	ia, err := c.iar.GetInfo(dctx, id)
	if err != nil {
		c.ErrServerError(ctx, 8, "保存失败", errors.Wrap(err, "读取信息失败："))
		return
	}
	// 检查是否需要审核
	if col.IsInfoChk == 1 {
		// 需要审核
		if err := ia.CommitCheck(dctx); err != nil {
			c.ErrServerError(ctx, 8, "保存失败", errors.Wrap(err, "提交审核失败："))
			return
		}

	} else {
		// 不需要审核直接发布
		if err := ia.Publish(dctx); err != nil {
			c.ErrServerError(ctx, 8, "保存失败", errors.Wrap(err, "提交审核失败："))
			return
		}
	}
	c.Success(ctx, map[string]interface{}{"info_id": id})
}

// ReqUpdateInfoDesc 更新请求
type ReqUpdateInfoDesc struct {
	Kind     int                    `json:"kind" binding:"required,gte=1,lte=5"`         // 类型 1.文章，2短文，3投票，4活动，5调查问卷
	Title    string                 `json:"title" binding:"required,max=100"`            // 标题
	SubTitle string                 `json:"sub_title,omitempty" binding:"max=100"`       // 副标题标题
	ListMode int                    `json:"list_mode,omitempty"`                         // 列表展示时的默认模式
	Icon     []string               `json:"icon,omitempty" binding:"max=9,dive,max=500"` // 图标
	Banner   string                 `json:"banner,omitempty" binding:"max=500"`          // 封面
	From     string                 `json:"from,omitempty" binding:"max=500"`            // 来源
	Desc     string                 `json:"desc,omitempty" binding:"max=500"`            // 简介
	Tags     []string               `json:"tags,omitempty" binding:"max=20,dive,max=20"` // 标签列表
	Content  string                 `json:"content,omitempty" binding:"max=5000"`        // 信息内容
	Extras   map[string]interface{} `json:"extras,omitempty" binding:"max=20"`           // 扩展信息
}

// To 转换为infod.InfoDesc
func (r ReqUpdateInfoDesc) To() infod.InfoDesc {
	return infod.InfoDesc{
		Kind:     r.Kind,
		Title:    r.Title,
		SubTitle: r.SubTitle,
		ListMode: r.ListMode,
		Icon:     r.Icon,
		From:     r.From,
		Banner:   r.Banner,
		Desc:     r.Desc,
		Tags:     r.Tags,
		Content:  r.Content,
		Extras:   r.Extras,
	}
}

type respStatus struct {
	Status infod.IStatus `json:"status"`
}

// 修改信息
// 只能修改当前用户自己的信息
// 如果信息所在栏目需要审核，修改成功后转为初始化状态，需要重新提交审核
func (c infoCtrl) updateInfoDesc(ctx *gin.Context) {

	infoid := ctx.Param("infoid")
	if infoid == "" {
		c.ErrBadRequest(ctx, 1, "请求参数错误")
		return
	}
	var req ReqUpdateInfoDesc

	if err := ctx.BindJSON(&req); err != nil {
		c.ErrBadRequestByBind(ctx, 2, err)
		return
	}

	dctx := c.DDDContext(ctx)

	uid := dctx.UID()
	if uid == "" {
		c.ErrUnauthorized(ctx, "未登录不能发布信息")
		return
	}
	i, err := c.iar.GetInfo(dctx, infoid)
	if err != nil {
		c.ErrServerError(ctx, 3, "保存失败", errors.Wrap(err, "检测信息是否存在失败."))
		return
	}
	if i == nil {
		c.ErrNotFound(ctx, 4, fmt.Sprintf("信息(%v)不存在", infoid))
		return
	}
	if i.Status != infod.IStatusInit &&
		i.Status != infod.IStatusCheckNO &&
		i.Status != infod.IStatusNoPublish &&
		i.Status != infod.IStatusCheckOk {
		c.ErrBadRequest(ctx, 41, "状态错误不能修改")
		return
	}
	desc := req.To()

	col, err := c.car.GetColumn(dctx, i.ColumnID)
	if err != nil {
		c.ErrServerError(ctx, 5, "保存失败", errors.Wrap(err, "检测栏目是否存在失败."))
		return
	}
	if col == nil {
		c.ErrBadRequest(ctx, 6, "栏目不存在")
		return
	}
	if col.Status != 0 {
		c.ErrBadRequest(ctx, 7, "栏目状态不对，不能修改信息")
		return
	}
	if col.Owner != "" && (col.Owner != uid || i.Owner != uid) {
		c.ErrForbidden(ctx, "无权限修改")
		return
	}
	// TODO 关于组织的校验还没有添加

	if col.Owner == "" && col.Org == "" && i.Creator != uid {
		c.ErrForbidden(ctx, "无权限修改")
		return
	}

	if err := util.CheckInfoExtral(col.Extras, req.Extras); err != nil {
		c.ErrServerError(ctx, 8, fmt.Sprintf("保存失败:%v", err.Error()), errors.Wrapf(err, "检测扩展属性失败。"))
		return
	}
	if col.InfoMode == columnd.InfoModeSingle {
		// 单文章模式发文章
		id, err := c.addSingleInfo(dctx, col, &desc)
		if err != nil {
			c.ErrServerError(ctx, 9, "保存失败", errors.Wrapf(err, "单文章模式发文失败"))
			return
		}
		c.Success(ctx, map[string]interface{}{"info_id": id})
		return
	}
	desc.ColumnID = i.ColumnID
	if col.IsInfoChk == columnd.On {
		if i.Status != infod.IStatusInit {

			// 需要将状态修改为初始化
			err = i.UpdateDescToInit(dctx, &desc)
			if err != nil {
				c.ErrServerError(ctx, 10, "保存失败", errors.Wrapf(err, "修改信息(%v)失败.", infoid))
				return
			}
			c.Success(ctx, respStatus{Status: infod.IStatusInit})
			return
		}
		// 修改不改变状态
		err = i.UpdateDesc(dctx, &desc)
		if err != nil {
			c.ErrServerError(ctx, 10, "保存失败", errors.Wrapf(err, "修改信息(%v)失败.", infoid))
			return
		}
		c.Success(ctx, respStatus{Status: infod.IStatusInit})
	}
	c.Success(ctx, respStatus{Status: i.Status})
}
func (c infoCtrl) deleteInfo(ctx *gin.Context) {

	infoid := ctx.Param("infoid")
	if infoid == "" {
		c.ErrBadRequest(ctx, 1, "请求参数错误")
		return
	}

	dctx := c.DDDContext(ctx)

	uid := dctx.UID()
	if uid == "" {
		c.ErrUnauthorized(ctx, "未登录不能删除信息")
		return
	}
	i, err := c.iar.GetInfo(dctx, infoid)
	if err != nil {
		c.ErrServerError(ctx, 3, "删除失败", errors.Wrap(err, "检测信息是否存在失败."))
		return
	}
	if i == nil {
		c.ErrNotFound(ctx, 4, fmt.Sprintf("信息(%v)不存在", infoid))
		return
	}
	if i.Owner != "" && i.Owner != uid {
		c.ErrForbidden(ctx, "无权限修改")
		return
	}
	// TODO 关于组织的校验还没有添加

	if i.Owner == "" && i.Org == "" && i.Creator != uid {
		c.ErrForbidden(ctx, "无权限修改")
		return
	}
	err = i.Delete(dctx)
	if err != nil {
		c.ErrServerError(ctx, 5, "删除失败", errors.Wrapf(err, "删除信息(%v)失败.", infoid))
		return
	}
	c.Success(ctx, nil)
}

// 发布操作
// 必须是当前用户所有信息才可以发布
// 当前信息发布栏目如果需要审核，信息状态为0的转为提交审核
func (c infoCtrl) publish(ctx *gin.Context) {
	infoid := ctx.Param("infoid")
	if infoid == "" {
		c.ErrBadRequest(ctx, 1, "请求参数错误")
		return
	}
	dctx := c.DDDContext(ctx)
	uid := dctx.UID()
	if uid == "" {
		c.ErrUnauthorized(ctx, "未登录不能发布信息")
		return
	}
	i, err := c.iar.GetInfo(dctx, infoid)
	if err != nil {
		c.ErrServerError(ctx, 3, "保存失败", errors.Wrap(err, "检测信息是否存在失败."))
		return
	}
	if i == nil {
		c.ErrNotFound(ctx, 4, fmt.Sprintf("信息(%v)不存在", infoid))
		return
	}
	if i.Owner != "" && i.Owner != uid {
		c.ErrForbidden(ctx, "无权限修改")
		return
	}
	// TODO 关于组织的校验还没有添加

	if i.Owner == "" && i.Org == "" && i.Creator != uid {
		c.ErrForbidden(ctx, "无权限修改")
		return
	}
	if i.Status == infod.IStatusInit {
		// 初始化状态检测是否需要审核
		// 获取栏目信息
		col, err := c.car.GetColumn(dctx, i.ColumnID)
		if err != nil {
			c.ErrServerError(ctx, 11, "保存失败", errors.Wrap(err, "检测栏目是否存在失败."))
			return
		}
		if col == nil {
			c.ErrBadRequest(ctx, 12, "栏目不存在")
			return
		}
		if col.Status != 0 {
			c.ErrBadRequest(ctx, 13, "栏目状态不对，不能修改信息")
			return
		}
		if col.IsChk == columnd.On {
			// 需要审核
			if err := i.CommitCheck(dctx); err != nil {
				c.ErrServerError(ctx, 14, "保存失败", errors.Wrapf(err, "保存信息(%v)失败.", infoid))
				return
			}
			c.Success(ctx, respStatus{Status: infod.IStatusCheckWait})
			return
		}
	}
	if err := i.Publish(dctx); err != nil {
		c.ErrServerError(ctx, 5, "保存失败", errors.Wrapf(err, "保存信息(%v)失败.", infoid))
		return
	}
	c.Success(ctx, respStatus{Status: infod.IStatusPublished})
}
func (c infoCtrl) unpublish(ctx *gin.Context) {

	infoid := ctx.Param("infoid")
	if infoid == "" {
		c.ErrBadRequest(ctx, 1, "请求参数错误")
		return
	}

	dctx := c.DDDContext(ctx)

	uid := dctx.UID()
	if uid == "" {
		c.ErrUnauthorized(ctx, "未登录不能发布信息")
		return
	}
	i, err := c.iar.GetInfo(dctx, infoid)
	if err != nil {
		c.ErrServerError(ctx, 3, "保存失败", errors.Wrap(err, "检测信息是否存在失败."))
		return
	}
	if i == nil {
		c.ErrNotFound(ctx, 4, fmt.Sprintf("信息(%v)不存在", infoid))
		return
	}
	if i.Owner != "" && i.Owner != uid {
		c.ErrForbidden(ctx, "无权限修改")
		return
	}
	// TODO 关于组织的校验还没有添加

	if i.Owner == "" && i.Org == "" && i.Creator != uid {
		c.ErrForbidden(ctx, "无权限修改")
		return
	}
	err = i.Unpublish(dctx)
	if err != nil {
		c.ErrServerError(ctx, 5, "保存失败", errors.Wrapf(err, "保存信息(%v)失败.", infoid))
		return
	}
	c.Success(ctx, nil)
}
func (c infoCtrl) updateInfoExtral(ctx *gin.Context) {

	infoid := ctx.Param("infoid")
	if infoid == "" {
		c.ErrBadRequest(ctx, 1, "请求参数错误")
		return
	}
	var req map[string]interface{}

	if err := ctx.BindJSON(&req); err != nil {
		c.ErrBadRequestByBind(ctx, 2, err)
		return
	}

	dctx := c.DDDContext(ctx)

	uid := dctx.UID()
	if uid == "" {
		c.ErrUnauthorized(ctx, "未登录不能发布信息")
		return
	}
	i, err := c.iar.GetInfo(dctx, infoid)
	if err != nil {
		c.ErrServerError(ctx, 3, "保存失败", errors.Wrap(err, "检测信息是否存在失败."))
		return
	}
	if i == nil {
		c.ErrNotFound(ctx, 4, fmt.Sprintf("信息(%v)不存在", infoid))
		return
	}
	col, err := c.car.GetColumn(dctx, i.ColumnID)
	if err != nil {
		c.ErrServerError(ctx, 5, "保存失败", errors.Wrap(err, "检测栏目是否存在失败."))
		return
	}
	if col == nil {
		c.ErrBadRequest(ctx, 6, "栏目不存在")
		return
	}
	if col.Status != 0 {
		c.ErrBadRequest(ctx, 7, "栏目状态不对，不能修改信息")
		return
	}
	if col.Owner != "" && (col.Owner != uid || i.Owner != uid) {
		c.ErrForbidden(ctx, "无权限修改")
		return
	}
	// TODO 关于组织的校验还没有添加

	if col.Owner == "" && col.Org == "" && i.Creator != uid {
		c.ErrForbidden(ctx, "无权限修改")
		return
	}
	if err := util.CheckInfoExtralForUpdate(col.Extras, req); err != nil {
		c.ErrServerError(ctx, 8, fmt.Sprintf("保存失败:%v", err.Error()), errors.Wrapf(err, "检测扩展属性失败。"))
		return
	}
	err = i.UpdateExtral(dctx, req)
	if err != nil {
		c.ErrServerError(ctx, 10, "保存失败", errors.Wrapf(err, "修改信息(%v)失败.", infoid))
		return
	}
	c.Success(ctx, nil)
}

func (c infoCtrl) addSingleInfo(dctx ddd.Context, col *columnd.ColumnAggregate, desc *infod.InfoDesc) (id string, err error) {
	pr, list, err := c.iar.QueryPage(dctx,
		infod.InfoSearch{
			ColumnID: col.ColumnID,
			Status: []infod.IStatus{
				infod.IStatusInit,
				infod.IStatusCheckWait,
				infod.IStatusCheckNO,
				infod.IStatusCheckOk,
				infod.IStatusNoPublish,
			},
		}, common.PageInfo{
			Mode:     0,
			PageSize: 1,
			Desc:     true,
		})
	if err != nil {
		return "", err
	}
	if pr.Total > 0 {
		// 已经有文章,如果有在编辑的文章不能新增
		for _, i := range list {
			// 已存在文章没有发布不能新增,只能修改
			return i.InfoID, i.UpdateDesc(dctx, desc)
		}
	}
	return c.iar.AddInfo(dctx, *desc)
}
